using System;
using System.Collections.Generic;
using SCG.SolarVengeanceEngine;
using SCG.SolarVengeanceEngine.StarShips;
using SCG.General;

namespace SCG.SolarVengeance.Scenarios
{
    public class OrbBattle : Scenario
    {
        #region Initializations

        private ScenarioParameter enbBH;
        private ScenarioParameter levelBH;
        private ScenarioParameter enbPL;
        private ScenarioParameter enbWH;
        private ScenarioParameter levelNeb;
        private ScenarioParameter VictoryTimer;
        private ScenarioParameter enbNeb;
        Freighter freight = null;
        private int _counter = 0;
        private Player _lastOwner = null;
        private Player owner = null;
        private Dictionary<Player, int> oShip = new Dictionary<Player, int>();
        Dictionary<Player, int> playerUDOs = new Dictionary<Player, int>();
        List<SCGPoint> pts = new List<SCGPoint>();
        List<SCGPoint> CircumferenceSCGPointsList = new List<SCGPoint>();

        public OrbBattle()
        {
            enbBH = CreateParameter("Black Holes Enabled?", 1, 0, 1);
            levelBH = CreateParameter("Level of Black Hole Strength", 3, 0, 5);
            enbPL = CreateParameter("Pulsars Enabled?", 1, 0, 1);
            enbWH = CreateParameter("Worm Holes Enabled?", 1, 0, 1);
            VictoryTimer = CreateParameter("Hold Orb for seconds:", 200, 100, 1000);
            enbNeb = CreateParameter("Desctuctive Nebula Enabled?", 1, 0, 1);
            levelNeb = CreateParameter("Level of Nebula Strength", 3, 0, 5);

        }

        public override string Description
        {
            get
            {
                return "The Tyrek sector was long fabled to contain an Orb of unknown origin, which was said to contain a limitless power source, that " +
                    "could tip the balance of power in the Galaxy.  A distress call from a lost freigher has finally confirmed it's existence, before " +
                    "it was destroyed in one of the many Black Holes of the sector.  The Star Lords, disregarding the dangers of this sector, have jumped their " +
                    "most powerful starfleets to capture posession of this crucial power source.  " +
                    "Notes:  Destructive Nebula strength is 0-5 (0 being no damage, 5 being most destructive)  " +
                    "Enabling Black Holes is not suggested for the faint of heart, because your starfleet may jump straight into one.";

            }
        }
        public override string Author
        {
            get
            {
                return "Ugly Green Things";
            }
        }

        public override PlayModeRecommendation Recommendation
        {
            get
            {
                return PlayModeRecommendation.MultiPlayer;
            }
        }

        //don't assign capitals
        public override bool AssignCapitals
        {
            get
            {
                return false;
            }
        }

        public override int MaxPlayers
        {
            get
            {
                return 8;
            }
        }

        public static double ConvertDegreesToRadians(double degrees)
        {
            double radians = (Math.PI / 180) * degrees;
            return (radians);
        }

        #endregion

        public override void BuildScenario(int numPlayers, int capitalValues, int startingResources)
        {
            #region Scenario Initializations

            //clear previously assigned dictionaries

            oShip.Clear();

            //Determine fleet values for each player, they all share equal strengths
            int commandRange = Random(8, 13);
            int scanRange = Random(9, 15);
            int bs = Random(30, 50);
            int stRange = Random(8, 13);
            int spyRange = Random(5, 9);

            //create the Orb  ("flag")
            
            int xO = Random(40, 60);
            int yO = Random(40, 60);
            UDO udo = CreateUDO("Orb", "Orb", xO, yO);          
            udo.Description = "Pick up the Orb by moving one of your StarShips over it.  Hold the orb for 100 impulses " +
                    "to win. The Orb may be transferred to another starship by using the Eject command.";
            udo.IsTaggable = true;
            udo.IgnoreBlackHoles = true;

            //Set-up table for Orb Carrier

            foreach (Player p in Game.Players)
                playerUDOs[p] = 0;

            //Set-up Fleet Positioning SCGPoints

            int Radius = 35;
            int CenterX = 50;
            int CenterY = 50;
            SCGPoint CircumferenceSCGPoint;

            for (double i = 0; i <= 360; i += 45)
            {
                // Replace last iteration SCGPoint with new empty SCGPoint struct

                CircumferenceSCGPoint = new SCGPoint();

                // Plot new SCGPoint on the circumference of a circle of the defined radius
                // Using the SCGPoint coordinates, radius, and angle
                // Calculate the position of this iterations SCGPoint on the circle

                CircumferenceSCGPoint.X = Convert.ToInt32(CenterX + Radius * Math.Cos(ConvertDegreesToRadians(i)));
                CircumferenceSCGPoint.Y = Convert.ToInt32(CenterY + Radius * Math.Sin(ConvertDegreesToRadians(i)));

                // Add newly plotted circumference SCGPoint to generic SCGPoint list

                CircumferenceSCGPointsList.Add(CircumferenceSCGPoint);
            }
             
            //Assign fleet locations of each player, make sure they are not too close to each other, and outside nebula

            int rand = 0;
            pts.Clear();

            foreach (Player p in Game.Players)
            {
                SCGPoint testSCGPoint = new SCGPoint();
                bool SCGPointOK = false;
                int loops = 0;
                oShip.Add(p, 0);

                do
                {
                    //get a random SCGPoint about 40 spaces away from center
                    loops++;
                    rand = Random(0, CircumferenceSCGPointsList.Count - 1);
                    testSCGPoint = CircumferenceSCGPointsList[rand];
                    //testSCGPoint.X = Random(10, 90);
                    //testSCGPoint.Y = Random(10, 90);
                    double dist = Distance(testSCGPoint.X, testSCGPoint.Y, 50, 50);
                    if (dist > 25 && dist < 45)
                    {
                        SCGPointOK = true;

                        //must also be at least 20 away from all other players
                        foreach (SCGPoint ptTest in pts)
                            if (Distance(testSCGPoint.X, testSCGPoint.Y, ptTest.X, ptTest.Y) < 15)
                            {
                                SCGPointOK = false;
                                break;
                            }
                    }
                }
                while (!SCGPointOK && loops < 10000000);
                if (loops >= 10000000)
                    DynamicEvents.DisplayMessage("Fleet positioning has timed out, and may not have positioned all fleets far apart.");

            #endregion

                #region Create StarFleets

                //this is the fleet location!
                pts.Add(testSCGPoint);
                oShip[p] = 0;

                //center Battlestation at this location
                int x = (int)testSCGPoint.X;
                int y = (int)testSCGPoint.Y;
                CreateStarShip(x, y, p, StarShipType.BattleStation, 6, bs, false);

                //create scanship
                CreateStarShip(x + 4, y, p, StarShipType.ScanShip, 20, scanRange, false);

                //create Drones
                for (int d = 0; d < 5; d++)
                {
                    CreateStarShip(x - 2 - d, y + 2, p, StarShipType.Drone, 12, 0, false);
                    CreateStarShip(x - 2 - d, y - 2, p, StarShipType.Drone, 12, 0, false);
                }

                //create W3 scouts
                for (int scout = 0; scout < 8; scout++)
                    CreateStarShip(x + 6, y - 4 + scout, p, StarShipType.WarShip, 14, 3, false);

                //create W4 battery
                for (int w4 = 0; w4 < 6; w4++)
                {
                    CreateStarShip(x + 5, y - 3 + w4, p, StarShipType.WarShip, 12, 4, false);
                }

                //create W6 battery & Elites
                for (int w6 = 0; w6 < 2; w6++)
                {
                    CreateStarShip(x - 4 - w6, y - 4, p, StarShipType.WarShip, 10, 6, false);
                    CreateStarShip(x - 4 - w6, y + 4, p, StarShipType.Elite, 20, 5, false);
                }


                //create SpyShip
                CreateStarShip(x + 2, y, p, StarShipType.SpyShip, 15, spyRange, false);

                //create CommandShip
                CreateStarShip(x + 3, y + 1, p, StarShipType.CommandShip, 20, commandRange, false);

                //create StarTillery
                CreateStarShip(x, y - 2, p, StarShipType.StarTillery, 20, stRange, false);
                CreateStarShip(x, y + 2, p, StarShipType.StarTillery, 20, stRange, false);

                //create cloaked groups
                for (int c = 0; c < 2; c++)
                {
                    CreateStarShip(x - c, y - 4, p, StarShipType.WarShip, 15, 7, true);
                    CreateStarShip(x - c, y + 4, p, StarShipType.WarShip, 15, 7, true);
                }

                //create Resource Freighters
                for (int f = 0; f < 3; f++)
                {
                    freight = CreateStarShip(x - 2 - f, y, p, StarShipType.Freighter, 6, 100, false) as Freighter;                  
                    freight.Resources = 1000;
                }
            }
                #endregion

            #region Create Map

            //Create Random Nebula
            int numNebula = SVGame.RNG.Next(4) + 2;
            while (numNebula > 0)
            {
                CreateNebula(SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(5) + 4, SVGame.RNG.Next(40) + 30);
                numNebula--;
            }
            //Create Random Wormholes
            int numWormholes = SVGame.RNG.Next(4) + 1;
            while (numWormholes > 0 && enbWH.Value == 1)
            {
                CreateWormhole(SVGame.RNG.Next(100), SVGame.RNG.Next(100), SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(40) + 30);
                numWormholes--;
            }
            numWormholes = SVGame.RNG.Next(4) + 1;
            while (numWormholes > 0 && enbWH.Value == 1)
            {
                CreateWormhole(SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(100), SVGame.RNG.Next(100));
                numWormholes--;
            }
            //Create Random Pulsars within the cluster
            int pulsars = Random(numPlayers, (numPlayers + 3));
            while (pulsars > 0 && enbPL.Value == 1)
            {
                SCGPoint ptPulsar = new SCGPoint();
                ptPulsar = new SCGPoint(Random(25, 75), Random(25, 75));
                CreatePulsar((int)ptPulsar.X, (int)ptPulsar.Y);
                pulsars--;
            }

            //Create Black Holes just outside the cluster perimeter
            int BlackHolesCreated = 0;
            Dictionary<int, int> BHInfoXpos = new Dictionary<int, int>();
            Dictionary<int, int> BHInfoYpos = new Dictionary<int, int>();
            int bhloops = 0;
            int bhX = 0;
            int bhY = 0;
            int BlackHoles = Random((numPlayers + 2), 10);
            while (BlackHoles > 0 && enbBH.Value == 1)
            {
                bool BlackHolesOK = false;
                SCGPoint ptBlackHoles = new SCGPoint();
                do
                {
                    bhloops++;
                    ptBlackHoles = new SCGPoint(Random(1, 99), Random(1, 99));
                    double dist = Distance(ptBlackHoles.X, ptBlackHoles.Y, 50, 50);
                    BlackHolesOK = dist > 45;
                    if (BlackHolesOK == true)
                    {
                        if (BlackHolesCreated > 0)
                        {
                            for (int d = 0; d < BlackHolesCreated; d++)
                            {
                                bhX = BHInfoXpos[d];
                                bhY = BHInfoYpos[d];
                                double bhdist = Distance(ptBlackHoles.X, ptBlackHoles.Y, bhX, bhY);
                                if (bhdist < 10)
                                    BlackHolesOK = false;
                            }
                        }
                    }
                }
                while (!BlackHolesOK && bhloops < 1000000);
                if (bhloops >= 1000000)
                    DynamicEvents.DisplayMessage("Black Hole positioning has timed out, and may not have positioned them correct.");
                else
                    CreateBlackHole((int)ptBlackHoles.X, (int)ptBlackHoles.Y, Random(levelBH.Value + 8, levelBH.Value + 10));
                BHInfoXpos.Add(BlackHolesCreated, (int)ptBlackHoles.X);
                BHInfoYpos.Add(BlackHolesCreated, (int)ptBlackHoles.Y);
                BlackHolesCreated++;
                BlackHoles--;
            }

            #endregion

        }

        #region Process Player Information and Victory Conditions

        #region On-screen Information/Timer

        //render visuals
        public override void CustomRendering(ISVCustomRenderer renderer)
        {
            renderer.DrawTextScreenCoords(_orbHeld, 8, 8, SCGColor.Red, 12);
            renderer.DrawTextScreenCoords(_possessed, 8, 28, SCGColor.Red, 12);
        }

        private string _orbHeld = "";
        private string _possessed = "";
        public override void ClientProcessImpulse(int impulse)
        {
            //render a timer for how long the Orb has been held
            string s = GetValue("Impulses");
            string t = GetValue("Posessed");

            if (s == "")
                s = "0";

            s = "The Orb has been held for: " + s + " impulses.";
            _orbHeld = s;
            
            if (t != "")   //check to make sure that there is not a "null" condition
                t = "Currently posessed by: " + t;
            else
                t = "Currently Unpossessed";
            _possessed = t;
        }

        #endregion

        #region Victory Conditions Processing
 
        public override bool VictoryReached()
        {
            #region Alternate Victory

            //If all of a players starships are destroyed

            #region Count Starships

            foreach (Player p in Game.Players)
            {
                oShip[p] = 0;
                foreach (StarShip s in Game.StarShips)
                {
                    if (s.Owner == p)
                        oShip[p]++;
                }
            #endregion

                #region Early Elimination

                if (oShip[p] == 0)
                    p.Eliminated = true;            

                #endregion
            }

            #endregion

            #region Normal Victory

            //Same Player must hold the Orb for a designated time period.

            if (owner != null)  //if Orb is picked-up
            {
                if (owner == _lastOwner)
                {
                    _counter++;
                    if (_counter >= VictoryTimer.Value)
                    {
                        _lastOwner.Victor = true;
                        return true;
                    }
                }
                else
                {
                    _lastOwner = owner;
                    _counter = 0;
                }
            }
            else   //reset timer if Orb is dropped.
                _lastOwner = null;
            return base.VictoryReached();

            #endregion
        }

        #endregion

        #region Dynamic Processing

        public override void ProcessImpulse(int impulse)
        {
            #region Destructive Nebula

            if (impulse == 1 && enbNeb.Value == 1)
            {
                DynamicEvents.DisplayMessage("Nebula is destructive to all starship types.");
            }

            if (enbNeb.Value == 1)
                foreach (StarShip ship in Game.StarShips)
                {
                    if (Game.GetTerrain(ship.X, ship.Y) == 'N' || Game.GetTerrain(ship.X, ship.Y) == 'n')
                    {
                        if (Random(0, 99) > (100 - levelNeb.Value * 19))
                        {
                            DynamicEvents.AdjustShipValues(ship, ship.Engines, ship.MaxEngines, ship.Value - 1, ship.MaxValue, true);
                        }
                        if (Random(0, 99) > (100 - levelNeb.Value * 19) && ship.Engines > 3)
                        {
                            DynamicEvents.AdjustShipValues(ship, ship.Engines - 1, ship.MaxEngines, ship.Value, ship.MaxValue, true);
                        }

                    }
                }

            #endregion;

            #region Orb Owner

            //Process the owner of the Orb
            //unused secondary count "n" for the number of UDOs being carried
            int n = 0;
            foreach (UDO udo in Game.UDOs)
                if (udo.Carrier != null)
                {
                    foreach (StarShip ship in Game.StarShips)
                        if (udo.Carrier == ship)
                        {
                            owner = ship.Owner;
                            n++;
                        }
                }
                else  //if Orb is not being carried, reset "owner" to "null" to stop the counter
                    owner = null;

            #endregion;

            #region Orb Falling into Black Hole Repositioning

            // Orb in Black Hole repositioning


            foreach (UDO udo in Game.UDOs)
                if (Game.GetObjectAt(udo.X, udo.Y) is BlackHole)
                {
                    DynamicEvents.CreateExplosion(udo.X, udo.Y, 50, SCGColor.Purple, SCGColor.Yellow, 4, 12, 200, true);               
                    SCGPoint udoRT = new SCGPoint();
                    udoRT.X = Random(40, 60);
                    udoRT.Y = Random(40, 60);                
                    DynamicEvents.MoveUDO(udo, (int)udoRT.X, (int)udoRT.Y);
                }

            #endregion;

            #region Client communication

            //communicate this information to clients


            SetValue("Impulses", _counter.ToString());
            if (owner != null) //check to make sure that there is not a "null" condition
                SetValue("Posessed", owner.ToString());
            else
                SetValue("Posessed", "");


            #endregion;
        }

        #endregion

        #endregion
    }
}





